package com.apes.fsm;

import org.squirrelframework.foundation.fsm.HistoryType;
import org.squirrelframework.foundation.fsm.StateCompositeType;
import org.squirrelframework.foundation.fsm.StateMachineBuilder;
import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory;
import org.squirrelframework.foundation.fsm.annotation.*;
import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine;


public class QuickStartSample {

    // 1. Define State Machine Event
    enum PEvent {
        A1a2A1b, A1a2B, A1b2A1a, A1b2A1c, A2a2A2b, A2b2A2a, A2b2A2c, A2B, B2A, Finish
    }

    // 2. Define State Machine Class
    enum PState {
        Total, A, A1, A1a, A1b, A1c, A2, A2a, A2b, A2c, B, C
    }


    @States({
            @State(name = "Total"),
            @State(name = "A", parent = "Total", compositeType = StateCompositeType.PARALLEL),
            @State(name = "A1", parent = "A"),
            @State(name = "A1a", parent = "A1", initialState = true, entryCallMethod="enter", exitCallMethod="exit"),
            @State(name = "A1b", parent = "A1", entryCallMethod="enter", exitCallMethod="exit"),
            @State(name = "A1c", parent = "A1", isFinal = true),
            @State(name = "A2", parent = "A", historyType = HistoryType.DEEP),
            @State(name = "A2a", parent = "A2"),
            @State(name = "A2b", parent = "A2", initialState = true),
            @State(name = "A2c", parent = "A2", isFinal = true),
            @State(name = "B", parent = "Total"),
            @State(name = "C", parent = "Total")
    })
    @Transitions({
            @Transit(from = "A", to = "B", on = "A2B"),
            @Transit(from = "B", to = "A", on = "B2A"),
            @Transit(from = "A1a", to = "A1b", on = "A1a2A1b"),
            @Transit(from = "A1a", to = "B", on = "A1a2B"),
            @Transit(from = "A1b", to = "A1a", on = "A1b2A1a"),
            @Transit(from = "A1b", to = "A1c", on = "A1b2A1c"),
            @Transit(from = "A2a", to = "A2b", on = "A2a2A2b"),
            @Transit(from = "A2b", to = "A2a", on = "A2b2A2a"),
            @Transit(from = "A2b", to = "A2c", on = "A2b2A2c"),
            @Transit(from = "A", to = "C", on = "Finish"),
    })
    @ContextEvent(finishEvent = "Finish")
    static class StateMachineSample extends AbstractStateMachine<StateMachineSample, PState, PEvent, Integer> {

//        @Override
//        protected void afterTransitionCompleted(PState fromState, PState toState, PEvent event, Integer context) {
//            System.out.println(String.format("from: %s , to: %s, event: %s", fromState, toState, event));
//        }

        public void enter(PState from, PState to, PEvent event, Integer context) {
            System.out.println(String.format("enter=====from: %s , to: %s, event: %s", from, to, event));
        }

        public void exit(PState from, PState to, PEvent event, Integer context) {
            System.out.println(String.format("exit=====from: %s , to: %s, event: %s", from, to, event));
        }
    }

    public static void main(String[] args) throws Exception {
        StateMachineBuilder<StateMachineSample, PState, PEvent, Integer> builder = StateMachineBuilderFactory.create
                (StateMachineSample.class, PState.class, PEvent.class, Integer.class);
        StateMachineSample fsm = builder.newStateMachine(PState.A);
        fsm.start();

//        DotVisitor visitor = SquirrelProvider.getInstance().newInstance(DotVisitor.class);
//        fsm.accept(visitor);
//        visitor.convertDotFile("HierarchicalStateMachine");

        System.out.println("=======================================");
        System.out.println("Current state is " + fsm.getCurrentState());
        fsm.getSubStatesOn(fsm.getCurrentState()).forEach(s -> {
            System.out.println("Current child state is " + s);
        });

        fsm.fire(PEvent.A1a2A1b, 10);

        System.out.println("=======================================");
        System.out.println("Current state is " + fsm.getCurrentState());
        fsm.getSubStatesOn(fsm.getCurrentState()).forEach(s -> {
            System.out.println("Current child state is " + s);
        });
    }

}